﻿//AcademicPlanner - course registration planning web app.
//Copyright (C) 2009  Boubacar Diallo

//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either version 2
//of the License, or (at your option) any later version.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.

//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.


using System;
using System.Collections.Generic;
using System.Linq;
using AcademicPlanner.Data;
using AcademicPlanner.Data.Entities;
using AcademicPlanner.Data.Repositories;
using AcademicPlanner.Framework.Libraries.Validation;
using AcademicPlanner.Framework.Helpers;

namespace AcademicPlanner.Domain.Models
{
	/// <summary>
	/// AcademicTerm represents an academic term in the application.
	/// </summary>
	/// <since>1.0</since>
    public class AcademicTerm : Model
    {
		/// <summary>
		/// Minimum value for the <c>OrderNum</c> property of a AcademicTerm: <c>0</c>.
		/// </summary>
		/// <since>1.0</since>
		public static readonly int ORDERNUM_MIN_VALUE = 0;

		/// <summary>
		/// Maximum value for the <c>OrderNum</c> property of a AcademicTerm: <c>10</c>.
		/// </summary>
		/// <since>1.0</since>
		public static readonly int ORDERNUM_MAX_VALUE = 10;

		/// <summary>
		/// The <c>AcademicPlan</c> this AcademicTerm belongs to.
		/// </summary>
		/// <since>1.0</since>
		protected AcademicPlan plan;


		/// <summary>
		/// Gets the data layer repository for this AcademicTerm's underlying data representation.
		/// </summary>
		/// <since>1.0</since>
		protected override EntityRepository EntityRepo { get { return DomainMaster.DSAS.AcademicTermEntityRepo; } }

		/// <summary>
		/// Gets this AcademicTerm's underlying data representation.
		/// </summary>
		/// <since>1.0</since>
		protected AcademicTermEntity Entity { get { return (AcademicTermEntity)entity; } }

		/// <summary>
		/// Gets this AcademicTerm's name.
		/// </summary>
		/// <since>1.0</since>
		public string Name
		{
			get
			{
				return Entity.Name;
			}
		}

		/// <summary>
		/// Gets this AcademicTerm's position in the year.
		/// </summary>
		/// <since>1.0</since>
		public int OrderNum
		{
			get
			{
				return Entity.Seq_Order;
			}
		}

		/// <summary>
		/// Gets the <c>AcademicPlan</c> this AcademicTerm belongs to.
		/// </summary>
		public AcademicPlan Plan
		{
			get
			{
				SetPlan();
				return plan;
			}
		}


		/// <summary>
		/// Constructs a new AcademicTerm.
		/// </summary>
		/// <remarks>
		/// This constructor invokes the matching super constructor.
		/// </remarks>
		/// <since>1.0</since>
		public AcademicTerm()
			: base()
		{
			
		}

		/// <summary>
		/// Constructs a new AcademicTerm with the provided <c>AcademicTermEntity</c>.
		/// </summary>
		/// <remarks>
		/// This constructor invokes the matching super constructor.
		/// </remarks>
		/// <param name="pEntity">The AcademicTerm's <c>AcademicTermEntity</c>.</param>
		/// <since>1.0</since>
		public AcademicTerm(AcademicTermEntity pEntity) 
			: base(pEntity)
		{
			
		}


		private void ResetPlan()
		{
			if (Entity.PlanEntity != null)
				plan = DomainMaster.ModelsFountain.GetAcademicPlan(Entity.PlanEntity);
		}

		private void SetPlan()
		{
			if (plan == null)
				ResetPlan();
		}

		internal void Set(string pName, int ? pOrderNum)
		{
			var vErrs = Validate(pName, pOrderNum);

			if (vErrs.OuterErrors.Count > 0)
				throw new InvalidModelPropertiesException(DomainErrorCode.M_INVALID_ACADEMICTERM_PROPERTIES, vErrs);

			SetPlan();
			if (plan != null)
			{
				vErrs = plan.ValidateTerm(entity.Id, pName ?? "", pOrderNum ?? 0);
				if (vErrs.OuterErrors.Count > 0)
					throw new InvalidModelPropertiesException(DomainErrorCode.M_INVALID_ACADEMICTERM_PROPERTIES, vErrs);
			}

			if (pName != null)
				Entity.Name = SecurityHelper.SanitizeInput(pName);
			if (pOrderNum != null)
				Entity.Seq_Order = (int)pOrderNum;
		}

		/// <summary>
		/// Validates possible values of a AcademicTerm's properties. <c>null</c> values are ignored.
		/// </summary>
		/// <remarks>
		/// <c>String</c> inputs are sanitized first.
		/// </remarks>
		/// <param name="pName">The name.</param>
		/// <param name="pOrderNum">The position in the year.</param>
		/// <returns>A Collection of validation errors.</returns>
		/// <seealso cref="M:ValidateName"/>
		/// <seealso cref="M:ValidateOrderNum"/>
		/// <seealso cref="M:AcademicPlanner.Framework.Helpers.SecurityHelper.SanitizeInput"/>
		/// <since>1.0</since>
		public static InvalidModelPropertiesErrorCollection Validate(string pName, int ? pOrderNum)
		{
			var rVal = new InvalidModelPropertiesErrorCollection("AcademicTerm");
			InvalidModelPropertyErrorCode vCode;

			if (pName != null)
			{
				if (!(vCode = ValidateName(SecurityHelper.SanitizeInput(pName)))
						.Equals(InvalidModelPropertyErrorCode.NONE))
					rVal.AddOuter("Name", vCode);
			}

			if (pOrderNum != null)
			{
				if (!(vCode = ValidateOrderNum((int)pOrderNum)).Equals(InvalidModelPropertyErrorCode.NONE))
					rVal.AddOuter("OrderNum", vCode);
			}

			return rVal;
		}

		/// <summary>
		/// Validates a possible value of a AcademicTerm's name.
		/// </summary>
		/// <remarks>
		/// The value must not be blank.
		/// </remarks>
		/// <param name="pVal">The value to validate.</param>
		/// <returns>A validation error code.</returns>
		/// <seealso cref="M:AcademicPlanner.Framework.Libraries.Validation.StringValidator.IsNotBlank"/>
		/// <since>1.0</since>
		public static InvalidModelPropertyErrorCode ValidateName(string pVal)
		{
			var rVal = InvalidModelPropertyErrorCode.NONE;

			if (!StringValidator.IsNotBlank(pVal))
				rVal = InvalidModelPropertyErrorCode.REQUIRED;

			return rVal;
		}

		/// <summary>
		/// Validates a possible value of a AcademicTerm's name.
		/// </summary>
		/// <remarks>
		/// The value must be between <see cref="P:ORDERNUM_MIN_VALUE"/>
		/// and <see cref="P:ORDERNUM_MAX_VALUE"/> exclusive.
		/// </remarks>
		/// <param name="pVal">The value to validate.</param>
		/// <returns>A validation error code.</returns>
		/// <since>1.0</since>
		public static InvalidModelPropertyErrorCode ValidateOrderNum(int pVal)
		{
			var rVal = InvalidModelPropertyErrorCode.NONE;

			if (pVal <= ORDERNUM_MIN_VALUE)
				rVal = InvalidModelPropertyErrorCode.TOO_SMALL;
			else if (pVal >= ORDERNUM_MAX_VALUE)
				rVal = InvalidModelPropertyErrorCode.TOO_LARGE;

			return rVal;
		}
    }
}
